{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 基于通义千问原生接口的ReAct代理实现\n",
    "https://python.langchain.com/docs/use_cases/tool_use/prompting/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#导入语言模型\n",
    "import os\n",
    "from langchain_community.llms import Tongyi\n",
    "from langchain_community.llms import SparkLLM\n",
    "from langchain_community.llms import QianfanLLMEndpoint\n",
    "\n",
    "import pandas as pd\n",
    "#导入模版\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "#导入聊天模型\n",
    "from langchain.prompts.chat import (\n",
    "    ChatPromptTemplate,\n",
    "    SystemMessagePromptTemplate,\n",
    "    AIMessagePromptTemplate,\n",
    "    HumanMessagePromptTemplate,\n",
    ")\n",
    "from langchain.schema import (\n",
    "    AIMessage,\n",
    "    HumanMessage,\n",
    "    SystemMessage\n",
    ")\n",
    "\n",
    "from langchain_community.chat_models import ChatSparkLLM\n",
    "from langchain_community.chat_models.tongyi import ChatTongyi\n",
    "from langchain_community.chat_models import QianfanChatEndpoint\n",
    "\n",
    "#输入三个模型各自的key\n",
    "\n",
    "os.environ[\"DASHSCOPE_API_KEY\"] = \"\"\n",
    "\n",
    "os.environ[\"IFLYTEK_SPARK_APP_ID\"] = \"\"\n",
    "os.environ[\"IFLYTEK_SPARK_API_KEY\"] = \"\"\n",
    "os.environ[\"IFLYTEK_SPARK_API_SECRET\"] = \"\"\n",
    "\n",
    "os.environ[\"QIANFAN_AK\"] = \"\"\n",
    "os.environ[\"QIANFAN_SK\"] = \"\"\n",
    "\n",
    "from operator import itemgetter\n",
    "from langchain_core.runnables import RunnableLambda, RunnablePassthrough\n",
    "from langchain_core.output_parsers import StrOutputParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_ty = Tongyi(temperature=0)\n",
    "model_qf = QianfanLLMEndpoint(model=\"ERNIE-Bot\")\n",
    "chat_qf = QianfanChatEndpoint(model=\"ERNIE-Bot\")\n",
    "chat_xh = ChatSparkLLM()\n",
    "chat_ty= ChatTongyi()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'0.1.9'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import langchain\n",
    "langchain.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "#! pip install --upgrade langchain -i https://mirrors.aliyun.com/pypi/simple\n",
    "#! pip install --upgrade langchain_community -i https://mirrors.aliyun.com/pypi/simple"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通义千问原生接口调用\n",
    "\n",
    "https://help.aliyun.com/zh/dashscope/developer-reference/api-details?spm=a2c4g.11186623.0.0.65eb12b0M4nTKZ\n",
    "\n",
    "https://blog.csdn.net/qq_53280175/article/details/134746680"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from dashscope import Generation\n",
    "import dashscope\n",
    "from langchain.tools.render import render_text_description\n",
    " \n",
    "dashscope.api_key = \"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_response(mess):\n",
    "    response = Generation.call(\n",
    "        model='qwen-turbo',\n",
    "        messages=mess,\n",
    "        result_format='message', # 将输出设置为message形式\n",
    "    )\n",
    "    return response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "GenerationResponse(status_code=<HTTPStatus.OK: 200>, request_id='57ea59d2-db83-9d9e-9a85-7f697f1b02ba', code='', message='', output=GenerationOutput(text=None, choices=[Choice(finish_reason='stop', message=Message({'role': 'assistant', 'content': 'Hello! How can I assist you today?'}))], finish_reason=None), usage=GenerationUsage(input_tokens=20, output_tokens=9))"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res=get_response([{\"content\":\"hi\",\"role\":\"user\"}])#user system assistant\n",
    "res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Hello! How can I assist you today?'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.output.choices[0].message[\"content\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模版的使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你是一个非常聪明的物理学教授。\n",
      "你擅长以简洁易懂的方式回答物理问题。\n",
      "当你不知道答案时，你会承认不知道。\n",
      "\n",
      "这是一个问题：\n",
      "量子力学有什么用\n"
     ]
    }
   ],
   "source": [
    "query=\"量子力学有什么用\"\n",
    "\n",
    "physics_template = f\"\"\"你是一个非常聪明的物理学教授。\n",
    "你擅长以简洁易懂的方式回答物理问题。\n",
    "当你不知道答案时，你会承认不知道。\n",
    "\n",
    "这是一个问题：\n",
    "{query}\"\"\"\n",
    "\n",
    "print(physics_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "res=get_response([{\"content\":physics_template,\"role\":\"user\"}])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "量子力学是一门基础且极其重要的物理学分支，它描述了微观世界的行为，如原子、分子、光子和更小粒子的运动。它的应用广泛且深远，尽管在日常生活中我们可能觉察不到，但对现代科技发展有着重大影响：\n",
      "\n",
      "1. **技术基础**：量子力学是现代信息技术的基石，包括量子计算、量子通信（如量子密钥分发）、以及量子密码学（如量子随机数生成）等前沿领域。\n",
      "\n",
      "2. **材料科学**：量子效应在新型材料如超导体、半导体、量子点和量子阱中起着关键作用，这些材料在电子设备（如电脑芯片）和太阳能电池等方面有重要应用。\n",
      "\n",
      "3. **医学成像**：核磁共振成像（MRI）就利用了量子力学中的核自旋现象。\n",
      "\n",
      "4. **能源**：量子力学原理在理解光合作用和太阳能电池的工作原理中不可或缺。\n",
      "\n",
      "5. **纳米技术**：在制造和操控极小尺度的物体时，量子力学的规则变得至关重要。\n",
      "\n",
      "6. **量子纠缠**：这是一种神奇的现象，两个粒子即使相隔遥远也能瞬间相互影响，这为量子通信提供了可能性。\n",
      "\n",
      "7. **基础研究**：量子力学本身也是物理学的基石，推动了我们对宇宙本质的理解，比如黑洞信息悖论和宇宙起源的研究。\n",
      "\n",
      "总的来说，量子力学不仅是理论研究的前沿，也是推动科技进步和社会发展的重要力量。\n"
     ]
    }
   ],
   "source": [
    "print(res.output.choices[0].message[\"content\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 与langchain工具的结合使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.tools import tool\n",
    "\n",
    "@tool\n",
    "def multiply(first_int: int, second_int: int) -> int:\n",
    "    \"\"\"将两个整数相乘。\"\"\"\n",
    "    return first_int * second_int\n",
    "\n",
    "@tool\n",
    "def add(first_int: int, second_int: int) -> int:\n",
    "    \"将两个整数相加。\"\n",
    "    return first_int + second_int\n",
    "\n",
    "@tool\n",
    "def exponentiate(base: int, exponent: int) -> int:\n",
    "    \"对底数求指数幂。\"\n",
    "    return base**exponent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.utils.function_calling import convert_to_openai_tool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'type': 'function',\n",
       " 'function': {'name': 'multiply',\n",
       "  'description': 'multiply(first_int: int, second_int: int) -> int - 将两个整数相乘。',\n",
       "  'parameters': {'type': 'object',\n",
       "   'properties': {'first_int': {'type': 'integer'},\n",
       "    'second_int': {'type': 'integer'}},\n",
       "   'required': ['first_int', 'second_int']}}}"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "convert_to_openai_tool(multiply)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_response_1t(mess):\n",
    "    response = Generation.call(\n",
    "        model='qwen-turbo',\n",
    "        messages=mess,\n",
    "        tools=[convert_to_openai_tool(multiply)],\n",
    "        result_format='message', # 将输出设置为message形式\n",
    "    )\n",
    "    return response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "res=get_response_1t([{\"content\":\"5加9\",\"role\":\"user\"}])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Choice(finish_reason='stop', message=Message({'role': 'assistant', 'content': '5加9等于14。这是一个基本的算术加法。如果你需要进一步的帮助或者有更复杂的数学问题，随时告诉我。'}))"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.output.choices[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### classwork 1\n",
    "\n",
    "* 通过通义千问使用一个工具\n",
    "* 一下是用LECL实现的一个多工具代理，请通过通义千问原生的工具接口实现多工具的择优"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[convert_to_openai_tool(i) for i in tools]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "tools = [add, exponentiate, multiply]\n",
    "\n",
    "def tool_chain(model_output):\n",
    "    tool_map = {tool.name: tool for tool in tools}\n",
    "    chosen_tool = tool_map[model_output[\"name\"]]\n",
    "    return itemgetter(\"arguments\") | chosen_tool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_response_3t(mess):\n",
    "    response = Generation.call(\n",
    "        model='qwen-turbo',\n",
    "        messages=mess,\n",
    "        tools=[convert_to_openai_tool(i) for i in tools],\n",
    "        result_format='message', # 将输出设置为message形式\n",
    "    )\n",
    "    return response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "res=get_response_3t([{\"content\":\"5加9\",\"role\":\"user\"}])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "res_agrs=res.output.choices[0].message['tool_calls'][0][\"function\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "res_agrs[\"arguments\"]=parser.parse(res_agrs[\"arguments\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'name': 'add', 'arguments': {'first_int': 5, 'second_int': 9}}"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res_agrs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "14"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t_run=tool_chain(res_agrs)\n",
    "t_run.invoke(res_agrs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.tools.render import render_text_description\n",
    "\n",
    "rendered_tools = render_text_description(tools)\n",
    "system_prompt = f\"\"\"您是一名助理，可以使用以下工具集。 以下是每个工具的名称和说明:\n",
    "\n",
    "{rendered_tools}\n",
    "\n",
    "根据用户输入，返回要使用的工具的名称和输入。 将您的响应作为带有'name'和'arguments'键的 JSON blob 返回，“arguments”键对应的值应该是所选函数的输入参数的字典，字典里不要有任何说明,此JSON blob必须是如下格式：```json\n",
    "...\n",
    "```\"\"\"\n",
    "\n",
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [(\"system\", system_prompt), (\"user\", \"{input}\")]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1237"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain = prompt | model_ty | JsonOutputParser() | tool_chain\n",
    "chain.invoke({\"input\": \"3加上1234\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'result': '2 + 2 = 4', 'mode': 'math_operation'}"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.utils.function_calling import convert_to_openai_tool\n",
    "from langchain_core.output_parsers import JsonOutputParser\n",
    "\n",
    "#tools_p=[convert_to_openai_tool(i) for i in tools]\n",
    "parser = JsonOutputParser()\n",
    "output_dict = parser.parse('{\"result\": \"2 + 2 = 4\", \"mode\": \"math_operation\"}')\n",
    "output_dict"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于ReAct提示词框架的代理实现\n",
    "\n",
    "### ReAct提示词框架\n",
    "\n",
    "原始论文：\n",
    "\n",
    "https://arxiv.org/pdf/2210.03629.pdf\n",
    "\n",
    "论文解读\n",
    "\n",
    "https://zhuanlan.zhihu.com/p/660951271\n",
    "\n",
    "\n",
    "langchain的实现方案解读\n",
    "\n",
    "https://cloud.tencent.com/developer/article/2286923\n",
    "\n",
    "https://cloud.tencent.com/developer/article/2267317\n",
    "\n",
    "langchain AgentExecutor方法的源代码：\n",
    "\n",
    "https://api.python.langchain.com/en/latest/_modules/langchain/agents/agent.html#AgentExecutor\n",
    "\n",
    "langchain 相关prompt 代码的地址：\n",
    "\n",
    "https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/agents/mrkl/prompt.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 基于通义千问的react代理实现\n",
    "\n",
    "* classwork 2\n",
    "\n",
    "1. 通义千问导入上面三个工具\n",
    "\n",
    "2. 借用langchain agent模版，构建模版函数，完成模型的初始调用\n",
    "\n",
    "3. 结合初次调用结果，形成下次调用的prompt，并完成二次调用\n",
    "\n",
    "4. 再次结合完成最终的调用\n",
    "\n",
    "5. 综合上面所有代码，构建循环完成一个ReAct代理的实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "PREFIX = \"\"\"Answer the following questions as best you can. You have access to the following tools:\"\"\"\n",
    "FORMAT_INSTRUCTIONS = \"\"\"Use the following format:\n",
    "\n",
    "Question: the input question you must answer\n",
    "Thought: you should always think about what to do\n",
    "Action: the action to take, should be one of [{tool_names}]\n",
    "Action Input: the input to the action\n",
    "Observation: the result of the action\n",
    "... (this Thought/Action/Action Input/Observation can repeat N times)\n",
    "Thought: I now know the final answer\n",
    "Final Answer: the final answer to the original input question\"\"\"\n",
    "SUFFIX = \"\"\"Begin!\n",
    "\n",
    "Question: {input}\n",
    "Thought:{agent_scratchpad}\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [],
   "source": [
    "tools = [add, exponentiate, multiply]\n",
    "parser = JsonOutputParser()\n",
    "output_dict = parser.parse('{\"result\": \"2 + 2 = 4\", \"mode\": \"math_operation\"}')\n",
    "tool_names=[i.name for i in tools]\n",
    "\n",
    "\n",
    "def prompt_react(input):\n",
    "    PREFIX = \"\"\"Answer the following questions as best you can. You have access to the following tools:\"\"\"\n",
    "    p0= f\"\"\"Use the following format:\n",
    "\n",
    "Question: the input question you must answer\n",
    "Thought: you should always think about what to do\n",
    "Action: the action to take in order, should be one of {tool_names}\n",
    "Action Input: the input to the action\n",
    "Observation: the result of the action\n",
    "... (this Thought/Action/Action Input/Observation can repeat N times)\n",
    "Thought: I now know the final answer\n",
    "Final Answer: the final answer to the original input question\n",
    "\n",
    "Begin!\n",
    "\n",
    "Question: {input}\n",
    "Thought:\"\"\"\n",
    "    return [{\"role\":\"system\",\"content\":PREFIX},{\"role\":\"user\",\"content\":p0}]\n",
    "\n",
    "def tool_chain(model_output):\n",
    "    tool_map = {tool.name: tool for tool in tools}\n",
    "    chosen_tool = tool_map[model_output[\"name\"]]\n",
    "    return itemgetter(\"arguments\") | chosen_tool\n",
    "\n",
    "def get_response_3t(mess):\n",
    "    response = Generation.call(\n",
    "        model='qwen-turbo',\n",
    "        messages=mess,\n",
    "        tools=[convert_to_openai_tool(i) for i in tools],\n",
    "        result_format='message', # 将输出设置为message形式\n",
    "    )\n",
    "    return response\n",
    "def get_args(res_c):\n",
    "    args0=res_c.split(\"\\nAction: \")[1].split(\"\\nAction Input:\")\n",
    "    return {\"name\":args0[0],\"arguments\":parser.parse(args0[1])}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 我们需要按照数学中的运算顺序来计算这个问题，先乘法后加法，最后是幂运算。所以步骤应该是：1. 5乘以6，2. 将结果加上4，3. 计算得到的和的四次方，4. 最后加上35。我会使用相应的工具来进行计算。\n",
      "Action: multiply\n",
      "Action Input: {\"first_int\": 5, \"second_int\": 6}\n",
      "Thought: 现在我们得到了乘法的结果，下一步是将这个结果加上4。\n",
      "Action: add\n",
      "Action Input: {\"first_int\": 30, \"second_int\": 4}\n",
      "Thought: 加上4后的结果是34，接下来我们需要对这个34进行四次方运算。\n",
      "Action: exponentiate\n",
      "Action Input: {\"base\": 34, \"exponent\": 4}\n",
      "Thought: 现在已经得到了四次方的结果，最后一步是把这个值加上35。\n",
      "Action: add\n",
      "Action Input: {\"first_int\": 1336336, \"second_int\": 35}\n",
      "Thought: 最终答案是1336371。\n",
      "Final Answer: 1336371\n",
      "Use the following format:\n",
      "\n",
      "Question: the input question you must answer\n",
      "Thought: you should always think about what to do\n",
      "Action: the action to take in order, should be one of ['add', 'exponentiate', 'multiply']\n",
      "Action Input: the input to the action\n",
      "Observation: the result of the action\n",
      "... (this Thought/Action/Action Input/Observation can repeat N times)\n",
      "Thought: I now know the final answer\n",
      "Final Answer: the final answer to the original input question\n",
      "\n",
      "Begin!\n",
      "\n",
      "Question: 4加5乘以6然后再算4次方然后再加35\n",
      "Thought: 我们需要按照数学中的运算顺序来计算这个问题，先乘法后加法，最后是幂运算。所以步骤应该是：1. 5乘以6，2. 将结果加上4，3. 计算得到的和的四次方，4. 最后加上35。我会使用相应的工具来进行计算。\n",
      "Action: multiply\n",
      "Action Input: {\"first_int\": 5, \"second_int\": 6}\n",
      "Observation: 30\n",
      "Thought: 现在我们得到了乘法的结果，下一步是将这个结果加上4。\n",
      "Action: add\n",
      "Action Input: {\"first_int\": 30, \"second_int\": 4}\n",
      "Observation: 34\n",
      "Thought: 加上4后的结果是34，接下来我们需要对这个34进行四次方运算。\n",
      "Action: exponentiate\n",
      "Action Input: {\"base\": 34, \"exponent\": 4}\n",
      "Observation: 1336336\n",
      "Thought: 现在已经得到了四次方的结果，最后一步是把这个值加上35。\n",
      "Action: add\n",
      "Action Input: {\"first_int\": 1336336, \"second_int\": 35}\n",
      "Observation: 1336371\n",
      "Thought: 最终答案是1336371。\n",
      "Final Answer: 1336371\n"
     ]
    }
   ],
   "source": [
    "p_r=prompt_react(\"4加5乘以6然后再算4次方然后再加35\")\n",
    "\n",
    "for i in range(0,8):\n",
    "    res=get_response_3t(p_r)\n",
    "    res_content=res.output.choices[0].message[\"content\"]\n",
    "    print(res_content)\n",
    "    if res_content.find(\"Action Input:\")!=-1:\n",
    "        args=get_args(res_content)\n",
    "        t_run=tool_chain(args)\n",
    "        p_r[1][\"content\"]=p_r[1][\"content\"]+res_content+\"\\nObservation: \"+str(t_run.invoke(args))+\"\\n\"\n",
    "    else:\n",
    "        p_r[1][\"content\"]=p_r[1][\"content\"]+res_content\n",
    "        break\n",
    "print(p_r[1][\"content\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 完整代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 我们需要先计算5和6的乘积，然后加上4，最后将这个结果立方。这涉及到两个数学步骤：乘法和幂运算。我会先做乘法，然后做幂运算。\n",
      "Action: multiply\n",
      "Action Input: {\"first_int\": 5, \"second_int\": 6}\n",
      "现在我得到了5和6的乘积，下一步是将其与4相加，然后计算这个和的三次方。\n",
      "Action: add\n",
      "Action Input: {\"first_int\": 30, \"second_int\": 4}\n",
      "我已经得到了34这个和，接下来我需要对34进行三次方运算。\n",
      "Action: exponentiate\n",
      "Action Input: {\"base\": 34, \"exponent\": 3}\n",
      "我已经计算出了最终的答案，5乘以6再加4的结果的三次方等于39,304。\n",
      "Final Answer: 39,304\n",
      "Use the following format:\n",
      "\n",
      "Question: the input question you must answer\n",
      "Thought: you should always think about what to do\n",
      "Action: the action to take in order, should be one of ['add', 'exponentiate', 'multiply']\n",
      "Action Input: the input to the action\n",
      "Observation: the result of the action\n",
      "... (this Thought/Action/Action Input/Observation can repeat N times)\n",
      "Thought: I now know the final answer\n",
      "Final Answer: the final answer to the original input question\n",
      "\n",
      "Begin!\n",
      "\n",
      "Question: 5乘以6加上4然后再算其3次方\n",
      "Thought: 我们需要先计算5和6的乘积，然后加上4，最后将这个结果立方。这涉及到两个数学步骤：乘法和幂运算。我会先做乘法，然后做幂运算。\n",
      "Action: multiply\n",
      "Action Input: {\"first_int\": 5, \"second_int\": 6}\n",
      "Observation: 30\n",
      "Thought:现在我得到了5和6的乘积，下一步是将其与4相加，然后计算这个和的三次方。\n",
      "Action: add\n",
      "Action Input: {\"first_int\": 30, \"second_int\": 4}\n",
      "Observation: 34\n",
      "Thought:我已经得到了34这个和，接下来我需要对34进行三次方运算。\n",
      "Action: exponentiate\n",
      "Action Input: {\"base\": 34, \"exponent\": 3}\n",
      "Observation: 39304\n",
      "Thought:我已经计算出了最终的答案，5乘以6再加4的结果的三次方等于39,304。\n",
      "Final Answer: 39,304\n"
     ]
    }
   ],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 百度千帆原生接口的使用\n",
    "\n",
    "https://cloud.baidu.com/doc/WENXINWORKSHOP/s/xlmokikxe#%E5%A4%9A%E8%BD%AE%E5%AF%B9%E8%AF%9D\n",
    "\n",
    "百度的特点：\n",
    "\n",
    "* 原生也支持function call\n",
    "* 默认会出发搜索工具，配合搜索工具产生答案"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [04-23 09:37:55] openapi_requestor.py:316 [t:8396]: requesting llm api endpoint: /chat/completions\n",
      "[INFO] [04-23 09:37:55] oauth.py:207 [t:8396]: trying to refresh access_token for ak `og6mWr***`\n",
      "[INFO] [04-23 09:37:55] oauth.py:220 [t:8396]: sucessfully refresh access_token\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "QfResponse(code=200, headers={'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Origin': '*', 'Appid': '53521775', 'Connection': 'keep-alive', 'Content-Encoding': 'gzip', 'Content-Type': 'application/json; charset=utf-8', 'Date': 'Tue, 23 Apr 2024 01:37:56 GMT', 'P3p': 'CP=\" OTI DSP COR IVA OUR IND COM \"', 'Server': 'Apache', 'Set-Cookie': 'BAIDUID=B165DBCFBE0BDB333783DFE61A98BC53:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2145916555; path=/; domain=.baidu.com; version=1', 'Statement': 'AI-generated', 'Vary': 'Accept-Encoding', 'X-Aipe-Self-Def': 'eb_total_tokens:24,prompt_tokens:1,id:as-z4wt2mr6i8', 'X-Baidu-Request-Id': 'sdk-py-0.3.2-9Je862bKWA1V6IZ4', 'X-Openapi-Server-Timestamp': '1713836275', 'X-Ratelimit-Limit-Requests': '300', 'X-Ratelimit-Limit-Tokens': '300000', 'X-Ratelimit-Remaining-Requests': '299', 'X-Ratelimit-Remaining-Tokens': '299999', 'Content-Length': '349'}, body={'id': 'as-z4wt2mr6i8', 'object': 'chat.completion', 'created': 1713836276, 'result': '你好！有什么我可以帮助你的吗？请随时告诉我你需要什么信息或者有什么问题，我会尽力回答和帮助你。', 'is_truncated': False, 'need_clear_history': False, 'search_info': {'is_beset': 0, 'rewrite_query': '', 'search_results': None}, 'finish_reason': 'normal', 'usage': {'prompt_tokens': 1, 'completion_tokens': 23, 'total_tokens': 24}}, statistic={'request_latency': 1.485118, 'total_latency': 1.4883869999999888}, request=QfRequest(method='POST', url='https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=24.338c8ff3d30c32424c592db595cd7e8b.2592000.1716428275.282335-53521775', query={}, headers={'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Request_id': 'sdk-py-0.3.2-9Je862bKWA1V6IZ4', 'Content-Length': '166', 'Content-Type': 'application/json'}, json_body={'enable_citation': True, 'messages': [{'role': 'user', 'content': '你好'}], 'stream': False, 'extra_parameters': {'request_source': 'qianfan_py_sdk_v0.3.2'}}, retry_config=RetryConfig(retry_count=1, timeout=10, max_wait_interval=120, backoff_factor=1, jitter=1, retry_err_codes={})))\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import qianfan\n",
    "\n",
    "# 使用安全认证AK/SK鉴权，通过环境变量初始化；替换下列示例中参数，安全认证Access Key替换your_iam_ak，Secret Key替换your_iam_sk\n",
    "os.environ[\"QIANFAN_ACCESS_KEY\"] = \"\"\n",
    "os.environ[\"QIANFAN_SECRET_KEY\"] = \"\"\n",
    "\n",
    "chat_comp = qianfan.ChatCompletion()\n",
    "\n",
    "# 指定特定模型\n",
    "resp = chat_comp.do(model=\"ERNIE-Bot\", messages=[{\n",
    "    \"role\": \"user\",\n",
    "    \"content\": \"你好\"\n",
    "}], enable_citation=True)\n",
    "\n",
    "print(resp)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 千帆自带的搜索工具触发"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [04-23 09:38:01] openapi_requestor.py:316 [t:8396]: requesting llm api endpoint: /chat/completions\n"
     ]
    }
   ],
   "source": [
    "def wenda_qf(mes):\n",
    "    resp = chat_comp.do(model=\"ERNIE-Bot\", messages=[{\n",
    "        \"role\": \"user\",\n",
    "        \"content\": mes\n",
    "    }], enable_citation=True)\n",
    "\n",
    "    return resp\n",
    "\n",
    "res=wenda_qf(\"杭州师范大学最近有什么新闻\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'id': 'as-r9x52wwhxs',\n",
       " 'object': 'chat.completion',\n",
       " 'created': 1713836290,\n",
       " 'result': '杭州师范大学最近的新闻有^[2]^：\\n\\n* **杭州师范大学主办2024年全国污染生态学学术研讨会** 。该研讨会于4月14日至16日在杭州召开，会议主题为\"污染生态与环境健康\"。\\n* **杭州师范大学本科教育教学审核评估线上评估启动会召开** 。该会议于4月15日下午召开，旨在全面贯彻落实省市\"新春第一会\"精神，坚持\"四个面向\"办教育，始终胸怀\"国之大者\"。\\n\\n此外，杭州师范大学还有召开第四届教职工代表大会等新闻^[1]^。',\n",
       " 'is_truncated': False,\n",
       " 'need_clear_history': False,\n",
       " 'search_info': {'is_beset': 0,\n",
       "  'rewrite_query': '杭州师范大学最近有什么新闻',\n",
       "  'search_results': [{'index': 1,\n",
       "    'url': 'https://www.hznu.edu.cn/test/xw/',\n",
       "    'title': '杭州师范大学新闻网',\n",
       "    'datasource_id': 'aurora-1'},\n",
       "   {'index': 2,\n",
       "    'url': 'https://www.hznu.edu.cn/index.shtml?eqid=ff9fff0a0004a2d600000004646f041c',\n",
       "    'title': '杭州师范大学',\n",
       "    'datasource_id': 'aurora-1'}]},\n",
       " 'finish_reason': 'normal',\n",
       " 'usage': {'prompt_tokens': 5, 'completion_tokens': 118, 'total_tokens': 123}}"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.body"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'is_beset': 0,\n",
       " 'rewrite_query': '杭州师范大学最近有什么新闻',\n",
       " 'search_results': [{'index': 1,\n",
       "   'url': 'https://www.hznu.edu.cn/test/xw/',\n",
       "   'title': '杭州师范大学新闻网',\n",
       "   'datasource_id': 'aurora-1'},\n",
       "  {'index': 2,\n",
       "   'url': 'https://www.hznu.edu.cn/index.shtml?eqid=ff9fff0a0004a2d600000004646f041c',\n",
       "   'title': '杭州师范大学',\n",
       "   'datasource_id': 'aurora-1'}]}"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.body[\"search_info\"]#保存搜索结果的位置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 百度千帆原生接口function call的使用\n",
    "\n",
    "https://www.cnblogs.com/szj666/p/17938812"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import qianfan\n",
    "import re\n",
    "from pprint import pprint\n",
    "import json\n",
    "prompt = \"想去北京天安门附近的10公里内的旅游景点\" \n",
    "\n",
    "def attractionRecommend(arguments):\n",
    "    return \"天坛公园\"\n",
    "def attractionReservation(arguments):\n",
    "    return \"预约成功\"\n",
    "def function_calling(prompt):\n",
    "    print(\"user-prompt:\"+prompt)\n",
    "    model = \"ERNIE-Bot\"\n",
    "    print('=' * 30,'大模型-',model,' 输出 ', '='*30,\"\\n\")\n",
    "    response = chat_comp.do(\n",
    "            model=model, \n",
    "            messages=[{\n",
    "                \"role\": \"user\",\n",
    "                \"content\": prompt\n",
    "                }],\n",
    "            temperature=0.000000001,\n",
    "            functions=[\n",
    "                {\n",
    "                    \"name\": \"attractionRecommend\",\n",
    "                    \"description\": \"景点推荐\",\n",
    "                    \"parameters\": {\n",
    "                        \"type\": \"object\",\n",
    "                        \"properties\": {\n",
    "                            \"location\": {\n",
    "                                \"type\": \"string\",\n",
    "                                \"description\": \"地址信息，包括省市、街道、门牌号等\"\n",
    "                                },\n",
    "                            \"expect_distance\": {\n",
    "                                \"type\": \"int\",\n",
    "                                \"description\": \"距离\"\n",
    "                                }\n",
    "                            },\n",
    "                        \"required\": [\"location\"]\n",
    "                        },\n",
    "                    \"responses\": {\n",
    "                        \"type\": \"object\",\n",
    "                        \"properties\": {\n",
    "                            \"price\": {\n",
    "                                \"type\": \"int\",\n",
    "                                \"description\": \"景点距离\"\n",
    "                                },\n",
    "                            \"food\": {\n",
    "                                \"type\": \"string\",\n",
    "                                \"description\": \"景点名称\"\n",
    "                                },\n",
    "                            },\n",
    "                        },\n",
    "                 },\n",
    "                 {\n",
    "                        \"name\": \"attractionReservation\",\n",
    "                        \"description\": \"景点介绍预约\",\n",
    "                        \"parameters\": {\n",
    "                            \"type\": \"object\",\n",
    "                            \"properties\": {\n",
    "                                \n",
    "                                \"attraction\": {\n",
    "                                    \"type\": \"string\",\n",
    "                                    \"description\": \"景点名称\"\n",
    "                                    },\n",
    "                                },\n",
    "                            \"required\": [\"attraction\"]\n",
    "                            },\n",
    "                        \"responses\": {\n",
    "                            \"type\": \"object\",\n",
    "                            \"properties\": {\n",
    "                                \"result\": {\n",
    "                                    \"type\": \"string\",\n",
    "                                    \"description\": \"回答完成\"\n",
    "                                    },\n",
    "                                }\n",
    "                            },\n",
    "                   }\n",
    "                 ]\n",
    "            )\n",
    "\n",
    "\n",
    "    pprint(response)\n",
    "    return response\n",
    "chat_comp = qianfan.ChatCompletion()\n",
    "\n",
    "\n",
    "prompt_list = re.split(r\"----\", prompt)\n",
    "\n",
    "for prompt in prompt_list:\n",
    "    response = function_calling(prompt)\n",
    "    function_name = response['body']['function_call']['name']\n",
    "    arguments = response['body']['function_call']['arguments']\n",
    "    print(eval(function_name)(arguments))\n",
    "    \n",
    "    #拿到response后，解析json，调用自定义的数据表api和下单api\n",
    "    print(\"\\n\")\n",
    "    print('=' * 30,\"大模型响应结束\",\"=\"*30)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
